#include "config.h"
#include "trim.h"

#include <fstream>
#include <iostream>
#include <string>
#include <sstream>

namespace verema
{

Config* Config::instance = 0;

Config::Config()
: _lang("")
, _dbname("")
, _view("")
, _unit("")
, _subunit("")
, _item("")
{
    //std::cout << "Config::Config()" << std::endl;
	parseConfig();
}

Config::Config(const verema::Config&)
{
	//std::cout<< "copy constructor called" << std::endl;
}

Config::~Config()
{
    //std::cout << "Config::~Config()" << std::endl;
}

Config* Config::getInstance()
{
	if( !instance )
	{
		instance = new Config();
	}

	return instance;
}

void Config::destroy()
{
	// static
	if( instance )
	{
        delete instance;
	}

	instance = 0;
}

void Config::parseConfig()
{
	std::ifstream configFile;
	configFile.open("config.ini");

	if (configFile.is_open())
	{
		while (configFile.good())
		{
			std::string line;
			size_t index;

			getline(configFile, line);

			if(line.substr(0,6) == "[main]")
			{
				//std::cout<< "[main] found" << std::endl;
			}
			else if(line.substr(0,4) == "lang")
			{
				index = line.find("=");
				if(index != std::string::npos)
				{
					_lang = line.substr(index + 1, line.length() - index - 1);
					tools::trim(_lang);
				}
			}
			else if(line.substr(0,6) == "dbname")
			{
				index = line.find("=");
				if(index != std::string::npos)
				{
					_dbname = line.substr(index + 1, line.length() - index - 1);
					tools::trim(_dbname);
				}
			}
			else if(line.substr(0,4) == "view")
			{
			    index = line.find("=");
			    if(index != std::string::npos)
			    {
			        _view = line.substr(index + 1, line.length() - index - 1);
			        tools::trim(_view);
			    }
			}
        }

		configFile.close();

        sqlite3 *_db;
        bool isOpen = false;
        int rc;

        if( _dbname.size() > 0 )
        {
            rc = sqlite3_open(_dbname.c_str(), &_db);
            if( rc == SQLITE_OK )
            {
                isOpen = true;

				int rc_unit, rc_subunit, rc_item;
				sqlite3_stmt *ppStmt_unit, *ppStmt_subunit, *ppStmt_item;
				const char *pzTail;

				std::string getUnit = "SELECT * FROM config WHERE name = 'unit';";
				std::string getSubunit = "SELECT * FROM config WHERE name = 'subunit';";
				std::string getItem = "SELECT * FROM config WHERE name = 'item';";

				rc_unit = sqlite3_prepare(_db, getUnit.c_str(), -1, &ppStmt_unit, &pzTail);
				if( rc_unit != SQLITE_OK )
				{
					std::cout<< "SQL: " << getUnit << std::endl;
					std::cout<< "Can't prepare statement: " << sqlite3_errmsg(_db) << std::endl;
				}
				else
				{
					rc_unit = sqlite3_step(ppStmt_unit);
					if( rc_unit == SQLITE_ROW )
					{
						_unit = reinterpret_cast<const char*>(sqlite3_column_text(ppStmt_unit, 1));
						rc_unit = sqlite3_finalize(ppStmt_unit);
					}
					else
					{
						std::cout<< "Can't step statement: " << sqlite3_errmsg(_db) << std::endl;
					}
				}

				rc_subunit = sqlite3_prepare(_db, getSubunit.c_str(), -1, &ppStmt_subunit, &pzTail);
				if( rc_unit != SQLITE_OK )
				{
					std::cout<< "SQL: " << getSubunit << std::endl;
					std::cout<< "Can't prepare statement: " << sqlite3_errmsg(_db) << std::endl;
				}
				else
				{
					rc_unit = sqlite3_step(ppStmt_subunit);
					if( rc_unit == SQLITE_ROW )
					{
						_subunit = reinterpret_cast<const char*>(sqlite3_column_text(ppStmt_subunit, 1));
						rc_unit = sqlite3_finalize(ppStmt_subunit);
					}
					else
					{
						std::cout<< "Can't step statement: " << sqlite3_errmsg(_db) << std::endl;
					}
				}

				rc_item = sqlite3_prepare(_db, getItem.c_str(), -1, &ppStmt_item, &pzTail);
				if( rc_item != SQLITE_OK )
				{
					std::cout<< "SQL: " << getItem << std::endl;
					std::cout<< "Can't prepare statement: " << sqlite3_errmsg(_db) << std::endl;
				}
				else
				{
					rc_item = sqlite3_step(ppStmt_item);
					if( rc_item == SQLITE_ROW )
					{
						_item = reinterpret_cast<const char*>(sqlite3_column_text(ppStmt_item, 1));
						rc_item = sqlite3_finalize(ppStmt_item);
					}
					else
					{
						std::cout<< "Can't step statement: " << sqlite3_errmsg(_db) << std::endl;
					}
				}

                if( isOpen )
                {
                    sqlite3_close(_db);
                }
            }
            else
            {
                std::cout<< "rc: " << rc << std::endl;
                std::cout<< "dbname: '" << _dbname << "'" << std::endl;
                std::cout<< "Can't open database: " << sqlite3_errmsg(_db) << std::endl;
            }
        }
        else
        {
            std::cout<< "Database could not be opened: No Filename!" << std::endl;
        }
	}
	else
	{
		_lang = "";
		_dbname = "";
		_view = "";
		_unit = "";
		_subunit = "";
		_item = "";
		std::cout << "config file not found!" << std::endl;
	}
}

void Config::lang(std::string lang_)
{
	_lang = lang_;
	writeConfig();
}

void Config::dbname(std::string dbname_)
{
	_dbname = dbname_;
	writeConfig();
}

void Config::view(std::string view_)
{
	_view = view_;
	writeConfig();
}

void Config::unit(std::string unit_)
{
	sqlite3 *_db;

    if( _dbname.size() > 0 )
    {
        int rc = sqlite3_open(_dbname.c_str(), &_db);
        if( rc == SQLITE_OK )
        {
			_unit = unit_;
			std::stringstream sql_stream(std::stringstream::in | std::stringstream::out);
			sql_stream << "UPDATE config SET value = '" << _unit << "' WHERE name = 'unit';";

			char *zErrMsg = 0;
			int temp_rc = sqlite3_exec(
				_db,
				sql_stream.str().c_str(),
				NULL,
				NULL,
				&zErrMsg);

            if( temp_rc != SQLITE_OK )
            {
                std::cout << "SQL error: " << zErrMsg << std::endl;
                sqlite3_free(zErrMsg);
            }
			sqlite3_close(_db);
		}
	}
}

void Config::subunit(std::string subunit_)
{
	sqlite3 *_db;

    if( _dbname.size() > 0 )
    {
        int rc = sqlite3_open(_dbname.c_str(), &_db);
        if( rc == SQLITE_OK )
        {
			_subunit = subunit_;
			std::stringstream sql_stream(std::stringstream::in | std::stringstream::out);
			sql_stream << "UPDATE config SET value = '" << _subunit << "' WHERE name = 'subunit';";

			char *zErrMsg = 0;
			int temp_rc = sqlite3_exec(
				_db,
				sql_stream.str().c_str(),
				NULL,
				NULL,
				&zErrMsg);

            if( temp_rc != SQLITE_OK )
            {
                std::cout << "SQL error: " << zErrMsg << std::endl;
                sqlite3_free(zErrMsg);
            }
			sqlite3_close(_db);
		}
	}
}

void Config::item(std::string item_)
{
	sqlite3 *_db;

    if( _dbname.size() > 0 )
    {
        int rc = sqlite3_open(_dbname.c_str(), &_db);
        if( rc == SQLITE_OK )
        {
			_item = item_;
			std::stringstream sql_stream(std::stringstream::in | std::stringstream::out);
			sql_stream << "UPDATE config SET value = '" << _item << "' WHERE name = 'item';";

			char *zErrMsg = 0;
			int temp_rc = sqlite3_exec(
				_db,
				sql_stream.str().c_str(),
				NULL,
				NULL,
				&zErrMsg);

            if( temp_rc != SQLITE_OK )
            {
                std::cout << "SQL error: " << zErrMsg << std::endl;
                sqlite3_free(zErrMsg);
            }
			sqlite3_close(_db);
		}
	}
}

void Config::writeConfig()
{
	std::ofstream configFile;
	configFile.open("config.ini");

	if (configFile.is_open())
	{
		configFile  << "[main]" << std::endl
					<< "lang\t= " << lang() << std::endl
					<< "dbname\t= " << dbname() << std::endl
					<< "view\t= " << view() << std::endl;

		configFile.close();
	}

	parseConfig();
}

} // namespace verema
